C# code generation
For C#, the compiler generates a .cs file from each .proto, with a class for each message type described in your file. https://protobuf.dev/reference/csharp/csharp-generated/
protoc --proto_path=src --csharp_out=build/gen --csharp_opt=file_extension=.g.cs,base_namespace=Example,internal_access src/foo.proto protoc --proto_path=bar --csharp_out=src --csharp_opt=base_namespace=Example player.proto
Fields
C# property for each field defined within a message. The exact nature of the property depends on the nature of the field: its type, and whether it is singular, repeated, or a map field.
Singular fields
Any singular field generates a read/write property. A string or bytes field will generate an ArgumentNullException if a null value is specified; fetching a value from a field which hasn’t been explicitly set will return an empty string or ByteString. Message fields can be set to null values, which is effectively clearing the field. This is not equivalent to setting the value to an "empty" instance of the message type.
Repeated
Each repeated field generates a read-only property of type Google.Protobuf.Collections.RepeatedField<T> where T is the field’s element type. For the most part, this acts like List<T>, but it has an additional Add overload to allow a collection of items to be added in one go. This is convenient when populating a repeated field in an object initializer. Additionally, RepeatedField<T> has direct support for serialization, deserialization and cloning, but this is usually used by generated code instead of manually-written application code.
Repeated fields cannot contain null values, even of message types, except for the nullable wrapper types explained below.
Map
Each map field generates a read-only property of type Google.Protobuf.Collections.MapField<TKey, TValue> where TKey is the field’s key type and TValue is the field’s value type. For the most part, this acts like Dictionary<TKey, TValue>, but it has an additional Add overload to allow another dictionary to be added in one go. This is convenient when populating a repeated field in an object initializer. Additionally, MapField<TKey, TValue> has direct support for serialization, deserialization and cloning, but this is usually used by generated code instead of manually-written application code. Keys in the map are not permitted to be null; values may be if the corresponding singular field type would support null values.
Oneof fields
Each field within a oneof has a separate property, like a regular singular field. However, the compiler also generates an additional property to determine which field in the enum has been set, along with an enum and a method to clear the oneof. For example, for this oneof field definition:
oneof avatar {
string image_url = 1;
bytes image_data = 2;
}
Will generate this:
enum AvatarOneofCase
{
None = 0,
ImageUrl = 1,
ImageData = 2
}
public AvatarOneofCase AvatarCase { get; }
public void ClearAvatar();
public string ImageUrl { get; set; }
public ByteString ImageData { get; set; }
If you have a message with many fields and where at most one field will be set at the same time, you can enforce this behavior and save memory by using the oneof feature.
Oneof fields are like regular fields except all the fields in a oneof share memory, and at most one field can be set at the same time. Setting any member of the oneof automatically clears all the other members. You can check which value in a oneof is set (if any) using a special case() or WhichOneof() method, depending on your chosen language.
If a property is the current oneof "case", fetching that property will return the value set for that property. Otherwise, fetching the property will return the default value for the property’s type—only one member of a oneof can be set at a time.
Setting any constituent property of the oneof will change the reported "case" of the oneof. As with a regular singular field, you cannot set a oneof field with a string or bytes type to a null value. Setting a message-type field to null is equivalent to calling the oneof-specific Clear method
Oneof features
- Setting a oneof field will automatically clear all other members of the oneof. So if you set several oneof fields, only the last field you set will still have a value.
- f the parser encounters multiple members of the same oneof on the wire, only the last member seen is used in the parsed message.
- can't be repeated
- If you set a oneof field to the default value (such as setting an int32 oneof field to 0), the “case” of that oneof field will be set, and the value will be serialized on the wire.
Namespaces
Tthe namespace to be used for the generated C# types. This option will be ignored when the .proto file is compiled for other languages. Protobuf files often contain language-specific options for several languages.
option csharp_namespace = "MyNamespace";
Importing definitions
import "myproject/other_protos.proto";
Generating packages
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto